/**
 * Project: complex.dal
 * 
 * File Created at 2011-3-14
 * $Id: SimpleDataSource.java 127 2011-03-15 12:14:22Z ymkyve501@163.com $
 * 
 * Copyright 1999-2100 Alibaba.com Corporation Limited.
 * All rights reserved.
 *
 * This software is the confidential and proprietary information of
 * Alibaba Company. ("Confidential Information").  You shall not
 * disclose such Confidential Information and shall use it only in
 * accordance with the terms of the license agreement you entered into
 * with Alibaba.com.
 */
package com.ymkyve.complex.dal;

/**
 * TODO Comment of SimpleDataSource
 * @author gaoliang
 *
 * @date 2011-3-14
 */
import java.io.PrintWriter;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
import java.util.Iterator;
import java.util.Queue;
import java.util.concurrent.ConcurrentLinkedQueue;

import javax.sql.DataSource;
 
@SuppressWarnings("unchecked")
public class SimpleDataSource implements DataSource {
 
    private String username;
    private String password;
    private String url;
 
    /*保存已经建立的连接*/
    private ConcurrentLinkedQueue connQueue = new ConcurrentLinkedQueue();
 
    public SimpleDataSource(String url, String driverClass, String username, String password)
            throws ClassNotFoundException {
        if (driverClass != null)
            Class.forName(driverClass);
        this.url = url;
        this.username = username;
        this.password = password;
    }
 
    public Connection getConnection() throws SQLException {
        Connection conn = (Connection) connQueue.poll();
        if (conn != null)
            return conn;
        conn = DriverManager.getConnection(url, username, password);
        return (Connection) Proxy.newProxyInstance( SimpleDataSource.class.getClassLoader(),
                                                    new Class[]{Connection.class},
                                                    new ConnectionInvocationHandler(conn, connQueue));
    }
 
    public void close() throws Throwable {
        Iterator it = connQueue.iterator();
        while (it.hasNext()) {
            Connection conn = (Connection) it.next();
            synchronized (conn) {
                try {
                    conn.close();
                }
                catch (Throwable e) {}
            }
        }
    }
 
    protected void finalize() throws Throwable {
        close();
    }
 
    static class ConnectionInvocationHandler implements InvocationHandler {
 
        private Connection conn;
 
        private Queue<Connection> connQueue;
 
        public ConnectionInvocationHandler(Connection conn, Queue connQueue) {
            this.conn = conn;
            this.connQueue = connQueue;
        }
 
        public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
            if (args == null
                && "close".equals(method.getName())
                && connQueue.size() < 20
                && connQueue.offer((Connection) proxy))
                return null;
            try {
                return method.invoke(conn, args);
            }
            catch (Throwable e) {
               // throw Lang.unwrapThrow(e);
                return null;
            }
        }
    }
 
    // -------------------------------------------------------------------------
    // 其他无需实现的方法
    // -------------------------------------------------------------------------
    public Connection getConnection(String username, String password) {
       return null;
    }
 
    public PrintWriter getLogWriter() throws SQLException {
       // throw Lang.noImplement();
        return null;
    }
 
    public int getLoginTimeout() throws SQLException {
        //throw Lang.noImplement();
        return 0;
    }
 
    public void setLogWriter(PrintWriter out) throws SQLException {
        //throw Lang.noImplement();
    }
 
    public void setLoginTimeout(int seconds) throws SQLException {
        //throw Lang.noImplement();
    }
 
    public boolean isWrapperFor(Class iface) throws SQLException {
        //throw Lang.noImplement();
        return true;
    }
 
    public Object unwrap(Class iface) throws SQLException {
        //throw Lang.noImplement();
        return null;
    }
}